C#アプリのパフォーマンス改善は、 UI・DB・非同期・メモリ・CPU の5つを押さえると一気に安定します。 この記事では、業務アプリで“本当に効く”高速化テクニックを体系的にまとめます。
この記事でわかること
・UI(WPF/WinForms)の高速化
・DB(SQLite/SQL Server)の最適化
・非同期処理(async/await)の正しい使い方
・LINQの高速化・メモリ削減
・キャッシュ戦略(メモリ/ローカルDB)
・プロファイリングでボトルネックを特定
・業務アプリ向けベストプラクティス
・UI(WPF/WinForms)の高速化
・DB(SQLite/SQL Server)の最適化
・非同期処理(async/await)の正しい使い方
・LINQの高速化・メモリ削減
・キャッシュ戦略(メモリ/ローカルDB)
・プロファイリングでボトルネックを特定
・業務アプリ向けベストプラクティス
1. パフォーマンス改善の基本方針
まずは闇雲に最適化するのではなく、 「どこが遅いか」を切り分けることが最重要です。
■ 1-1. 遅い箇所の分類
- UIが固まる → UIスレッド問題
- 検索が遅い → DB or LINQ
- 起動が遅い → 初期ロード or 設定ファイル
- APIが遅い → ネットワーク or シリアライズ
■ 1-2. 計測してから改善する
var sw = Stopwatch.StartNew();
DoWork();
Console.WriteLine(sw.ElapsedMilliseconds + "ms");
「なんとなく遅い」ではなく、数字で判断します。
2. UI高速化(WPF / WinForms)
■ 2-1. UIスレッドで重い処理をしない
await Task.Run(() => HeavyWork());
UIフリーズの9割は「UIスレッドで重い処理をしている」ことが原因です。
■ 2-2. DataGridに全件バインドしない
- ページング(100〜500件)
- 仮想化(Virtualization)ON
<DataGrid
EnableRowVirtualization="True"
VirtualizingPanel.IsVirtualizing="True"
VirtualizingPanel.ScrollUnit="Pixel"
/>
■ 2-3. Bindingの数を減らす
大量のBindingはCPUを圧迫します。 固定値はコードビハインドで設定する方が軽いです。
3. DB高速化(SQLite / SQL Server)
■ 3-1. インデックス設計(最重要)
CREATE INDEX idx_orders_user_date ON Orders(UserId, OrderDate);
WHERE句・JOIN句に使う列には必ずインデックスを貼ります。
■ 3-2. 全件取得禁止 → ページング必須
SELECT * FROM Logs
ORDER BY Id
LIMIT @limit OFFSET @offset;
■ 3-3. SQLiteはWALモードで高速化
PRAGMA journal_mode = WAL;
読み書きの競合が減り、ロックが大幅に減ります。
■ 3-4. バルクINSERTで高速化
using var tran = con.BeginTransaction();
foreach (var item in items)
{
con.Execute(sql, item, tran);
}
tran.Commit();
1件ずつINSERTするのは絶対にNGです。
4. 非同期処理(async/await)
■ 4-1. I/Oは必ず非同期
- DBアクセス
- ファイルI/O
- API呼び出し
var json = await http.GetStringAsync(url);
■ 4-2. Task.WhenAllで並列化
await Task.WhenAll(
LoadMasterAsync(),
LoadSettingsAsync(),
LoadUserAsync()
);
順番に待つより圧倒的に速くなります。
5. LINQ高速化(CPU削減)
■ 5-1. Where → ToList → Select の連続は遅い
LINQは「遅延実行」なので、無駄な列挙が発生しがちです。
■ 5-2. 最適化例
// 悪い例
var result = list.Where(x => x.Age > 20).ToList();
var names = result.Select(x => x.Name).ToList();
// 良い例(1回で済む)
var names = list
.Where(x => x.Age > 20)
.Select(x => x.Name)
.ToList();
■ 5-3. ForEachよりforの方が速い
大量データでは for が最速です。
6. メモリ最適化(GC負荷軽減)
■ 6-1. 大量の new を避ける
特にループ内での new はGCを圧迫します。
■ 6-2. StringBuilderを使う
var sb = new StringBuilder();
for (int i = 0; i < 10000; i++)
{
sb.Append(i);
}
■ 6-3. 配列・Listの容量を事前に確保
var list = new List<int>(capacity: 10000);
再確保(Resize)が減り、速度が安定します。
7. キャッシュ戦略(メモリ / ローカルDB)
■ 7-1. マスターデータはメモリキャッシュ
private readonly Dictionary<int, User> _cache = new();
public async Task<User> GetUserAsync(int id)
{
if (_cache.TryGetValue(id, out var u))
return u;
var user = await _repo.FindAsync(id);
_cache[id] = user;
return user;
}
■ 7-2. API結果はSQLiteにキャッシュ
オフライン対応にもなるため業務アプリでよく使われます。
8. プロファイリングでボトルネックを特定
- dotnet-trace
- dotnet-counters
- Visual Studio Profiler
- PerfView
「どこが遅いか」を可視化すると改善が一気に進みます。
9. 業務アプリ向けベストプラクティス
- UIスレッドで重い処理をしない(Task.Run)
- DataGridはページング+仮想化
- DBはインデックス+ページング+WAL
- LINQは遅延実行に注意し、1回で処理する
- 大量データはforループ+StringBuilder
- キャッシュを積極的に使う
- プロファイリングで根拠を持って改善する
まとめ:C#のパフォーマンス改善は“設計 × 非同期 × DB × メモリ”で決まる
- UI・DB・非同期・メモリをセットで最適化
- LINQ・GC・I/Oの理解が高速化の鍵
- キャッシュとプロファイリングで安定性UP
「アプリが重い」「画面が固まる」「検索が遅い」 という現場の悩みに対して、 この記事のテクニックはすべて即効性があります。 あなたのプロジェクトに合わせて最適な改善策を組み合わせてみてください。